package com.example.springsecuritydemo.exception;

import com.dong9.leke.common.support.RestResult;
import com.dong9.leke.common.support.RestResult.EnumResultCode;
import org.apache.commons.lang.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.SQLException;
import java.util.stream.Collectors;

/**
 * controller 异常的拦截处理
 * @author chenggang
 * @date 2019/04/08
 */
@RestControllerAdvice
public class BaseExceptionAdvice {

	private static final Logger logger = LoggerFactory.getLogger(BaseExceptionAdvice.class);
	
    @ExceptionHandler(value = BaseException.class)
    public RestResult<Object> errorHandler(BaseException ex) {
		RestResult<Object> result = new RestResult<Object>();
		result.setCode(ex.getCode());
		result.setMessage(ex.getMessage());
		return result;
	}

    @ExceptionHandler(value = MethodArgumentNotValidException.class)
	public RestResult<Object> methodArgumentHandler(MethodArgumentNotValidException ex) {
		RestResult<Object> result = new RestResult<Object>();
		String message=ex.getBindingResult().getFieldErrors().stream()
        .map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining("\n"));
		result.setCode(EnumResultCode.FAIL.getCode());
		result.setMessage(message);
		return result;
	}

    @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
	public RestResult<Object> methodNotSupportedHandler(HttpRequestMethodNotSupportedException ex) {
		RestResult<Object> result = new RestResult<Object>();
		result.setCode(EnumResultCode.FAIL.getCode());
		result.setMessage(ex.getMessage());
		return result;
	}
    
    @ExceptionHandler(IllegalArgumentException.class)
    public RestResult<Object> illegalArgumentException(IllegalArgumentException ex){
    	logger.info("参数异常: IllegalArgumentException={}", ex.getMessage());
    	logger.error("ex={}", ex);
        RestResult<Object> result = new RestResult<Object>();
		result.setCode(EnumResultCode.FAIL.getCode());
		result.setMessage("参数异常"+ex.getMessage());
		return result;
    }
	
    
    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public RestResult<Object> httpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException ex) {
    	logger.info("HttpMediaTypeNotSupportedException: ", ex.getMessage());
        RestResult<Object> result = new RestResult<Object>();
		result.setCode(EnumResultCode.FAIL.getCode());
		result.setMessage(ex.getMessage());
		return result;
    }
    
    @ExceptionHandler(Exception.class)
    public RestResult<Object> defaultHandler(HttpServletRequest request, Exception exception) {
    	  logger.error("Exception: ", exception);
        StringBuffer url = request.getRequestURL();
        String params = request.getQueryString();
        // 发生地点
        int lineNum = 0;
        String className = null;
        String methodName = null;
        StackTraceElement[] st = exception.getStackTrace();
        if (ArrayUtils.isNotEmpty(st)) {
            lineNum = st[0].getLineNumber();
            className = st[0].getClassName();
            methodName = st[0].getMethodName();
        }
        String message = exception.getMessage();
        logger.error("Exception: {}#{}() 在第{}行发生{}异常!!! url: {}, params: {}, info: {}", className, methodName, lineNum,
                exception.getClass().getName(), url, params, message);
        RestResult<Object> result = new RestResult<Object>();
		result.setCode(EnumResultCode.FAIL.getCode());
		result.setMessage(message);
		//TODO异常发送给钉钉
        return result;
    }
    

    @ExceptionHandler(SQLException.class)
    public RestResult<Object> sqlException(SQLException ex){
    	logger.info("SQLException: ", ex);
    	RestResult<Object> result = new RestResult<Object>();
        result.setCode(EnumResultCode.FAIL.getCode());
        result.setMessage("数据库操作失败");
    	return result;
    }
    
  
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public RestResult<Object> methodArgumentTypeMismatchException(MethodArgumentTypeMismatchException ex, HttpServletResponse response) {
    	logger.info("参数类型转换失败: MethodArgumentTypeMismatchException={}", ex.getMessage());
    	logger.error("参数类型转换失败: MethodArgumentTypeMismatchException={}", ex);
    	RestResult<Object> result = new RestResult<Object>();
        result.setCode(EnumResultCode.FAIL.getCode());
        result.setMessage("参数类型转换失败");
        return result;
    }
    
    
}
